home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / wildmat.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  5KB  |  188 lines

  1. /*
  2.  * @(#)wildmat.c 1.3 87/11/06   Public Domain.
  3.  *
  4. From: rs@mirror.TMC.COM (Rich Salz)
  5. Newsgroups: net.sources
  6. Subject: Small shell-style pattern matcher
  7. Message-ID: <596@mirror.TMC.COM>
  8. Date: 27 Nov 86 00:06:40 GMT
  9.  
  10. There have been several regular-expression subroutines and one or two
  11. filename-globbing routines in mod.sources.  They handle lots of
  12. complicated patterns.  This small piece of code handles the *?[]\
  13. wildcard characters the way the standard Unix(tm) shells do, with the
  14. addition that "[^.....]" is an inverse character class -- it matches
  15. any character not in the range ".....".  Read the comments for more
  16. info.
  17.  
  18. For my application, I had first ripped off a copy of the "glob" routine
  19. from within the find(1) source, but that code is bad news:  it recurses
  20. on every character in the pattern.  I'm putting this replacement in the
  21. public domain.  It's small, tight, and iterative.  Compile with -DTEST
  22. to get a test driver.  After you're convinced it works, install in
  23. whatever way is appropriate for you.
  24.  
  25. I would like to hear of bugs, but am not interested in additions; if I
  26. were, I'd use the code I mentioned above.
  27. */
  28. /*
  29. **  Do shell-style pattern matching for ?, \, [], and * characters.
  30. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  31. **  could cause a segmentation violation.
  32. **
  33. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  34. */
  35.  
  36. /*
  37.  * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
  38.  * if the pattern is immediately followed by a "/", as well as \0.
  39.  * This matches what "tar" does for matching whole subdirectories.
  40.  *
  41.  * The "*" code could be sped up by only recursing one level instead
  42.  * of two for each trial pattern, perhaps, and not recursing at all
  43.  * if a literal match of the next 2 chars would fail.
  44.  */
  45.  
  46. /* Modified by Anders Klemets to take an array of pointers as an optional
  47.    argument. Each part of the string that matches '*' is returned as a
  48.    null-terminated, malloced string in this array.
  49.  */
  50. #include <ctype.h>
  51. #include "global.h"
  52.  
  53.  
  54. static int Star __ARGS((char *s,char *p,char **argv,int single));
  55. static int haveDot __ARGS((register char *c,register int len));
  56.  
  57. static int
  58. haveDot(s,len)
  59. register char *s;
  60. register int len;
  61. {
  62.     while (len-- > 0)
  63.         if (*s++ == '.')
  64.             return TRUE;
  65.     return FALSE;
  66. }
  67.  
  68. static int
  69. Star(s,p,argv,single)
  70. register char *s;
  71. register char *p;
  72. register char **argv;
  73. int single;
  74. {
  75.     char *cp = s;
  76.     while (wildmat(cp, p, argv) == FALSE)
  77.         if(*++cp == '\0')
  78.             return -1;
  79.     if ((single == TRUE) && haveDot(s, cp - s))
  80.         return -1;
  81.     return cp - s;
  82. }
  83.  
  84. int
  85. wildmat(s,p,argv)
  86. register char *s;
  87. register char *p;
  88. register char **argv;
  89. {
  90.     register int last;
  91.     register int matched;
  92.     register int reverse;
  93.     register int cnt;
  94.     int single;
  95.  
  96.     for(; *p; s++,p++){
  97.         switch(*p){
  98.         case '\\':
  99.             /* Literal match with following character; fall through. */
  100.             p++;
  101.         default:
  102.              /*   if(*s != *p)   */
  103.              if (tolower(*s) != tolower(*p))
  104.                 return FALSE;
  105.             continue;
  106.         case '?':
  107.             /* Match anything. */
  108.             if(*s == '\0')
  109.                 return FALSE;
  110.             continue;
  111.         case '*':
  112.         case '+':
  113.             single = (*p == '+');
  114.  
  115.             /* Trailing star matches everything. */
  116.             if(argv == NULLCHARP)
  117.                 return *++p ? 1 + Star(s, p, NULLCHARP, single) : TRUE;
  118.             if(*++p == '\0'){
  119.                 cnt = strlen(s);
  120.                 if ((single == TRUE) && haveDot(s, cnt))
  121.                     return FALSE;
  122.             } else {
  123.                 if((cnt = Star(s, p, argv+1, single)) == -1)
  124.                     return FALSE;
  125.             }
  126.             *argv = mallocw((unsigned)cnt+1);
  127.             strncpy(*argv,s,(size_t)cnt);
  128.             *(*argv + cnt) = '\0';
  129.             return TRUE;
  130.         case '[':
  131.             /* [^....] means inverse character class. */
  132.             reverse = (p[1] == '^' || p[1] == '!') ? TRUE : FALSE;
  133.             if(reverse)
  134.                 p++;
  135.             for(last = 0400, matched = FALSE; *++p && *p != ']'; last = *p){
  136.                 /* This next line requires a good C compiler. */
  137.                 if(*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  138.                     matched = TRUE;
  139.             }
  140.             if(matched == reverse)
  141.                 return FALSE;
  142.             continue;
  143.         }
  144.     }
  145.     /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
  146.     return *s == '\0' || *s == '/';
  147. }
  148.  
  149.  
  150. #ifdef  TEST
  151. #include <stdio.h>
  152.  
  153. extern char *gets();
  154.  
  155. main()
  156. {
  157.     char pattern[80];
  158.     char text[80];
  159.     char *argv[80], *cp;
  160.     int cnt;
  161.     
  162.     while (TRUE){
  163.         printf("Enter pattern:  ");
  164.         if(gets(pattern) == NULL)
  165.             break;
  166.         while (TRUE){
  167. #ifdef UNIX
  168.             memset(argv, 0, 80 * sizeof (char *));
  169. #else
  170.             bzero(argv,80*sizeof(char *));
  171. #endif
  172.             printf("Enter text:  ");
  173.             if(gets(text) == NULL)
  174.                 exit(0);
  175.             if(text[0] == '\0')
  176.                 /* Blank line; go back and get a new pattern. */
  177.                 break;
  178.             printf("      %d\n", wildmat(text, pattern, argv));
  179.             for(cnt = 0; argv[cnt] != NULLCHAR; ++cnt){
  180.                 printf("String %d is: '%s'\n",cnt,argv[cnt]);
  181.                 free(argv[cnt]);
  182.             }
  183.         }
  184.     }
  185.     exit(0);
  186. }
  187. #endif  /* TEST */
  188.